package com.quwan.security.auth;

import com.alibaba.fastjson.JSONObject;
import com.quwan.anno.UpdateAccessTime;
import com.quwan.app.service.DispatchOrderService;
import com.quwan.app.service.MemberService;
import com.quwan.app.service.OrderService;
import com.quwan.app.service.PaymentService;
import com.quwan.app.vo.MemberDashboardData;
import com.quwan.common.BaseController;
import com.quwan.common.Check;
import com.quwan.common.enums.AuthFaceEnum;
import com.quwan.common.enums.DeviceEnum;
import com.quwan.common.enums.LoginEnum;
import com.quwan.common.exception.ExpCode;
import com.quwan.common.exception.ResponseException;
import com.quwan.common.result.ApiResult;
import com.quwan.component.AsyncTaskComponent;
import com.quwan.component.ComponentFactory;
import com.quwan.constans.AppConst;
import com.quwan.constans.CacheKey;
import com.quwan.entity.TGuest;
import com.quwan.entity.TGuestAppleBuy;
import com.quwan.entity.TMember;
import com.quwan.entity.TMemberAlbum;
import com.quwan.mapper.TGuestAppleBuyMapper;
import com.quwan.security.JwtProperties;
import com.quwan.security.JwtTokenUtil;
import com.quwan.security.auth.vo.AppLoginParams;
import com.quwan.security.auth.vo.LoginResult;
import com.quwan.utils.Parse;
import com.quwan.utils.redis.Redis;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.validation.constraints.Pattern;
import java.lang.reflect.InvocationTargetException;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author quan
 * @date 2021-06-07 16:02
 */

@Api(tags = "App登录")
@Slf4j
@Validated
@RestController
@RequiredArgsConstructor
@RequestMapping("auth")
public class AppLoginController extends BaseController {
    private final MemberService memberService;
    private final AsyncTaskComponent taskComponent;
    private final AuthenticationManager authenticationManager;
    private final ComponentFactory componentFactory;
    private final DispatchOrderService dispatchOrderService;
    private final JwtTokenUtil jwtTokenUtil;
    private final PaymentService paymentService;
    private final TGuestAppleBuyMapper appleBuyMapper;
    private final OrderService orderService;
    private final Redis redis;
    @Autowired
    private HttpServletRequest request;

    @ApiOperation("App发送手机验证码")
    @PostMapping("app_login/sendCode")
    public ApiResult verifyCode(@Pattern(regexp = AppConst.PHONE_REGEXP, message = "请输入正确的手机号码")
                                @ApiParam("手机号码") @RequestParam String mobile) {
        if (!memberService.generatePhoneVcode(mobile)) return ApiResult.error("服务器繁忙稍后重试");
        return ApiResult.success();

    }

    @Deprecated
    @ApiOperation("App手机验证码登录 return token 响应 code=8000 会返回新token  ")
    @PostMapping("app_login/vcode")
    public ApiResult<String> verifyCodeLogin(@Pattern(regexp = AppConst.PHONE_REGEXP, message = "请输入正确的手机号码")
                                             @ApiParam("手机号") @RequestParam String mobile,
                                             @ApiParam("验证码") @RequestParam String code,
                                             @ApiParam("推广用户id 可以null") Long parentId,
                                             @ApiParam("游客id 进行过游客登录 传id 没有游客登录可以不传") String guestId) {
        String token = memberService.vCodeLogin(mobile, code, parentId, guestId);
        taskComponent.addLoginRecord(Long.parseLong(String.valueOf(jwtTokenUtil.getClaimsInfo(token).get("userId"))), 2, request.getHeader(DeviceEnum.HEADER));
        return ApiResult.success(token);
    }

    @Deprecated
    @ApiOperation("App密码登录 return token 响应 code=8000 会返回新token ")
    @PostMapping("app_login/pwd")
    public ApiResult<String> passwordLogin(@Pattern(regexp = AppConst.PHONE_REGEXP, message = "请输入正确的手机号码")
                                           @ApiParam("手机号") @RequestParam("acc") String mobile,
                                           @ApiParam("密码") @RequestParam("pwd") String password) {
        String account = String.format("%s@@" + AppConst.MEMBER_MODULE, mobile);
        Authentication authentication = null;
        try {
            authentication =
                    authenticationManager.authenticate(
                            new UsernamePasswordAuthenticationToken(account, password));
        } catch (BadCredentialsException e) {
            return ApiResult.error(ExpCode.LOGIN_ERR);
        } catch (AuthenticationException e) {
            throw new ResponseException(ExpCode.LOGIN_ERR.getCode(), ExpCode.LOGIN_ERR.getMsg());
        }
        String token = jwtTokenUtil.generateToken((UserDetails) authentication.getPrincipal());
        taskComponent.addLoginRecord(Long.parseLong(String.valueOf(jwtTokenUtil.getClaimsInfo(token).get("userId"))), 2, request.getHeader(DeviceEnum.HEADER));
        return ApiResult.success(token);
    }

    @UpdateAccessTime
    @ApiOperation("App获取用户基本信息 " +
            "app加载时调用 请求头 需token 如获取不到数据 用户需要重新登录")
    @GetMapping("getMemberBaseInfo")
    public ApiResult<MemberDashboardData> memberInfo(HttpServletRequest request) {
        BaseController.TokenInfo tokenInfo = getTokenInfo(request);
        MemberDashboardData member = memberService.memberCacheInfo(tokenInfo.getId());
     //   member.setAlbums(memberService.getMemberAlbumsByMId(tokenInfo.getId()).stream().map(TMemberAlbum::getUrl).collect(Collectors.toList()));
        member.setIdentityBool("true".equalsIgnoreCase(member.getIdentity()));
        member.setFaceBool(AuthFaceEnum.FINISH.getCode().equals(member.getFaceStatus()));
        member.setMobileBool(StringUtils.isNotBlank(member.getMobile()));
        member.setShowDispatchOrder(dispatchOrderService.existsDispatchOrder(tokenInfo.getId()));
        member.setShowServiceOrder(orderService.existsPublishOrder(tokenInfo.getId()));
        member.setShowBuyItOrder(orderService.existsBuyItOrder(tokenInfo.getId()));
        member.setExistsApplyOrder(dispatchOrderService.existsApplyOrder(member.getId()));
        member.setExistsDispatchOrder(dispatchOrderService.existsDispatchOrders(member.getId()));
        member.setHomeBackground(memberService.getHomeBackground(member.getId()));
        member.setFirstName(Parse.toStr(redis.hGet(CacheKey.DATA.updNickname, member.getId()), member.getNickName()));
        return ApiResult.success(member);
    }

    @Deprecated
    @ApiOperation("游客登录")
    @PostMapping("app/guestLogin")
    public ApiResult<TGuest> guestLogin(@ApiParam("设备id") @RequestParam String deviceId) {
        return ApiResult.success(memberService.guestLogin(deviceId));
    }

    @ApiOperation(value = "App登录",
            notes = "type:登录类型 0-ios 1-wx 2-手机登录 3-密码 4-游客" +
                    "<br/>type: 0 1 首次调用type code参数非空," +
                    "<br/>返回参数(code=0 带openid参数返回 需调用信息接口发送验证码 提交手机号 验证码 openId,type)code=1 用户存在,返回token参数" +
                    "<br/>(type=2 mobile phoneCode 非空)(type 3 mobile password 非空)(type 4 guestId 传设备id)  " +
                    "<br/>(type:0 1 2 3) parentId guestId 如果没有可以不传" +
                    "<br/>type:4游客登录 guestId传的是设备id")
    @PostMapping("app/login")
    public ApiResult<LoginResult> appleLogin(@Pattern(regexp = AppConst.PHONE_REGEXP, message = "请输入正确的手机号码")
                                             @ApiParam("手机号") @RequestParam(required = false) String mobile,
                                             @ApiParam("调起授权页获取到的code") @RequestParam(required = false) String code,
                                             @ApiParam("openId") @RequestParam(required = false) String openId,
                                             @ApiParam("password") @RequestParam(required = false) String password,
                                             @ApiParam("0-ios登录 1-wx 2-手机登录 3-密码 4-游客") @RequestParam String type,
                                             @ApiParam("验证码") @RequestParam(required = false) String phoneCode,
                                             @ApiParam("推广用户id 可以null") @RequestParam(required = false) String parentId,
                                             @ApiParam("游客id 进行过游客登录 传id 没有游客登录可以不传") @RequestParam(required = false) String guestId,
                                             @ApiParam("ios唯一识别码") @RequestParam(required = false) String unique
    ) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {

        Function<AppLoginParams, LoginResult> instance = componentFactory.getLoginInstance(LoginEnum.getByType(type));
        LoginResult res = instance.apply(new AppLoginParams(code, openId, mobile, password, phoneCode, parentId, guestId));
        if (res.getCode().equals(ExpCode.AUTH_CODE_FAIL.getCode() + ""))
            throw new ResponseException(ExpCode.AUTH_CODE_FAIL.getCode(), ExpCode.AUTH_CODE_FAIL.getMsg());
        try {
            if (StringUtils.isNotBlank(unique)) {
                TGuestAppleBuy guestBuy = appleBuyMapper.selectById(unique);
                if (guestBuy != null && guestBuy.getStatus() == 1) {
                    paymentService.doGrantVip(jwtTokenUtil.getClaimsInfo(res.getToken()).get("userId").toString(), JSONObject.parseObject(guestBuy.getData()));
                    appleBuyMapper.updateById(new TGuestAppleBuy().setKey(guestBuy.getKey()).setStatus(0));
                }


            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return ApiResult.success(res);


    }

    private final JwtProperties jwtProperties;

    @ApiOperation("刷新token")
    @PostMapping("app/refresh_token")
    public ApiResult<String> refreshToken(HttpServletRequest request, @RequestParam(required = false) @ApiParam("token") String token) {
        String header = request.getHeader(jwtProperties.getHeader());

        if (StringUtils.isBlank(token) && StringUtils.isBlank(header))
            return ApiResult.error("token参数异常");

        if (StringUtils.isNotBlank(header))
            token = header.replace(jwtProperties.getTokenHead(), "").trim();

        Claims claims = null;
        try {
            claims = jwtTokenUtil.getClaimsFromToken(token);
        } catch (ExpiredJwtException e) {
            claims = e.getClaims();

        } catch (Exception ex) {
            log.error("无效的token参数");
            return ApiResult.error("无效的token");
        }

        if (claims == null)
            return ApiResult.error(ExpCode.LOGIN_TOKEN_EXPIRED);

        Object userId = claims.get("userId");
        TMember member = memberService.getMemberInfoById(String.valueOf(userId));
        Check.notNull(member, ExpCode.MEMBER_NOT_EXIST);
        if (member.getStatus() != 1)
            return ApiResult.error("用户已被禁用");
        String ret = jwtTokenUtil.generateToken(claims);

        return ApiResult.success(ret);
    }


}